package com.naiterui.common.repository.page;

import java.lang.reflect.Method;
import java.util.function.Function;

import org.springframework.util.ReflectionUtils;

import com.naiterui.common.repository.exception.DataConvertException;

/**
 * spring-data-jpa分页查询返回的Page对象支持map操作，
 * 用户将结果集中的实体对象转换为指定类型的对象，其参数是Convert接口，具体行为交由用户自行定义，
 * 该类是Convert接口一个简单实现，目前的实现方式:
 * VO类中自行定义一个名为convert的方法，方法内部实现从Entity -> VO的赋值操作
 * 此处通过反射直接调用convert方法来实现映射操作
 *
 * @author zhouyanxin
 * @since 1.0.0
 */
public final class SimplePageContentConvert<S, T> implements Function<S, T> {

    /**
     * 目标对象中执行转换逻辑的默认方法名称
     */
    private static final String DEFAULT_METHOD_NAME = "convertPageElement";

    /**
     * 目标对象的类型
     */
    private Class<T> targetClass;

    /**
     * 构造函数
     *
     * @param targetClass
     */
    public SimplePageContentConvert(Class<T> targetClass) {
        this.targetClass = targetClass;
    }

    /**
     * S为Page结果集中实体对象的类型，T为目标对象的类型
     * 通过反射读获取目标对象上通过@EntityField注解标注在属性上的配置
     * 然后以S对象作为源进行数据向T对象的赋值，从而完成转换工作
     *
     * @param source
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年8月21日
     * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
     * @since 1.0.0
     */
    @Override
    public T apply(S source) {

        // 实例化目标对象
        T targetObj = null;
        try {
            targetObj = this.targetClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new DataConvertException(
                    "execute Page mapping failed, can not initialize target object!", e);
        }

        // 获取目标对象声明的全部成员属性
        // Field[] fields = targetClass.getDeclaredFields();

        // 遍历全部属性并尝试读取注解信息用以构造目标对象
        /*for (Field field : fields) {
        
            // 为属性设置访问权限，由于目标对象是VO对象目前暂不考虑安全风险，如果在VM配置安全策略则此处需要修改为通过set方法进行赋值
            RepositoryReflectionUtils.makeAccessible(field);
        
            // 获取当前属性名称在源(类S)上对应的属性名，如果未设置注解或者采用默认值则视为与当前属性名一致
            EntityField annotation = field.getDeclaredAnnotation(EntityField.class);
            String originFieldName = field.getName();
            if (annotation != null && !StringUtils.isEmpty(originFieldName)) {
                originFieldName = annotation.name();
            }
        
            // 获取类S上对应属性的值
            Method targetMethod = RepositoryReflectionUtils.findGetterMethodByFieldName(source
                    .getClass(), originFieldName);
            Object rtnValue = ReflectionUtils.invokeMethod(targetMethod, source);
        
            // 将返回值赋值给目标对象(T)的当前属性
            RepositoryReflectionUtils.setField(field, targetObj, rtnValue);
        }*/

        // 执行自定义的赋值逻辑
        Method customMethod = ReflectionUtils.findMethod(this.targetClass, DEFAULT_METHOD_NAME, source.getClass());
        if (customMethod != null) {
            ReflectionUtils.invokeMethod(customMethod, targetObj, source);
        } else {
            throw new DataConvertException("execute Page mapping failed, not found suitable method，expect [void convert(" + source.getClass() + ")]");
        }

        return targetObj;
    }
}
